﻿namespace PerpetuumSoft.InstrumentationPDA.Mathematics
{
    using System;
    using System.Drawing;
    using System.Runtime.InteropServices;

    [StructLayout(LayoutKind.Sequential)]
    public struct VectorRectangle
    {
        private decimal x;
        private decimal y;
        private decimal width;
        private decimal height;
        public decimal X
        {
            get
            {
                return this.x;
            }
            set
            {
                this.x = value;
            }
        }
        public decimal Y
        {
            get
            {
                return this.y;
            }
            set
            {
                this.y = value;
            }
        }
        public decimal Width
        {
            get
            {
                return this.width;
            }
            set
            {
                this.width = value;
            }
        }
        public decimal Height
        {
            get
            {
                return this.height;
            }
            set
            {
                this.height = value;
            }
        }
        public Vector Location
        {
            get
            {
                return new Vector(this.x, this.y);
            }
            set
            {
                this.x = value.X;
                this.y = value.Y;
            }
        }
        public Vector Size
        {
            get
            {
                return new Vector(this.width, this.height);
            }
            set
            {
                this.width = value.X;
                this.height = value.Y;
            }
        }
        public decimal Top
        {
            get
            {
                return this.y;
            }
        }
        public decimal Bottom
        {
            get
            {
                return (this.y + this.height);
            }
        }
        public decimal Left
        {
            get
            {
                return this.x;
            }
        }
        public decimal Right
        {
            get
            {
                return (this.x + this.width);
            }
        }
        public Vector TopLeft
        {
            get
            {
                return new Vector(this.Left, this.Top);
            }
        }
        public Vector BottomLeft
        {
            get
            {
                return new Vector(this.Left, this.Bottom);
            }
        }
        public Vector TopRight
        {
            get
            {
                return new Vector(this.Right, this.Top);
            }
        }
        public Vector BottomRight
        {
            get
            {
                return new Vector(this.Right, this.Bottom);
            }
        }
        public decimal CenterX
        {
            get
            {
                return (this.x + (this.width / 2M));
            }
        }
        public decimal CenterY
        {
            get
            {
                return (this.y + (this.height / 2M));
            }
        }
        public Vector TopCenter
        {
            get
            {
                return new Vector(this.CenterX, this.Top);
            }
        }
        public Vector BottomCenter
        {
            get
            {
                return new Vector(this.CenterX, this.Bottom);
            }
        }
        public Vector LeftCenter
        {
            get
            {
                return new Vector(this.Left, this.CenterY);
            }
        }
        public Vector RightCenter
        {
            get
            {
                return new Vector(this.Right, this.CenterY);
            }
        }
        public Vector Center
        {
            get
            {
                return new Vector(this.CenterX, this.CenterY);
            }
        }
        public VectorRectangle(decimal x, decimal y, decimal width, decimal height)
        {
            this.x = x;
            this.y = y;
            this.width = width;
            this.height = height;
        }

        public VectorRectangle(Vector location, Vector size) : this(location.X, location.Y, size.X, size.Y)
        {
        }

        public VectorRectangle(Rectangle rect) : this(rect.X, rect.Y, rect.Width, rect.Height)
        {
        }

        public VectorRectangle(RectangleF rect) : this((decimal) rect.X, (decimal) rect.Y, (decimal) rect.Width, (decimal) rect.Height)
        {
        }

        public override int GetHashCode()
        {
            return base.GetHashCode();
        }

        public decimal Area()
        {
            return (this.width * this.height);
        }

        public bool Contains(Vector v)
        {
            return (((this.Left <= v.X) && (v.X <= this.Right)) && ((this.Top <= v.Y) && (v.Y <= this.Bottom)));
        }

        public VectorRectangle PositiveRectangle()
        {
            decimal x = Math.Min(this.Left, this.Right);
            decimal y = Math.Min(this.Top, this.Bottom);
            decimal width = Math.Abs(this.Width);
            return new VectorRectangle(x, y, width, Math.Abs(this.Height));
        }

        public VectorRectangle Quant(decimal xGrid, decimal yGrid)
        {
            return new VectorRectangle(this.Location.Quant(xGrid, yGrid), this.Size.Quant(xGrid, yGrid));
        }

        public VectorRectangle QuantX(decimal xGrid)
        {
            return new VectorRectangle(this.Location.QuantX(xGrid), this.Size.QuantX(xGrid));
        }

        public VectorRectangle QuantY(decimal yGrid)
        {
            return new VectorRectangle(this.Location.QuantY(yGrid), this.Size.QuantY(yGrid));
        }

        public bool IsEmpty
        {
            get
            {
                return ((this.width == 0M) && (this.height == 0M));
            }
        }
        public override bool Equals(object o)
        {
            try
            {
                return (this == ((VectorRectangle) o));
            }
            catch
            {
                return false;
            }
        }

        public static bool operator ==(VectorRectangle v1, VectorRectangle v2)
        {
            return ((v1.Location == v2.Location) && (v1.Size == v2.Size));
        }

        public static bool operator !=(VectorRectangle v1, VectorRectangle v2)
        {
            if (v1.Location == v2.Location)
            {
                return !(v1.Size == v2.Size);
            }
            return true;
        }

        public override string ToString()
        {
            return ("{(" + this.Location.ToString() + ";" + this.Size.ToString() + "}");
        }

        public static implicit operator VectorRectangle(Rectangle rect)
        {
            return new VectorRectangle(rect);
        }

        public static implicit operator VectorRectangle(RectangleF rect)
        {
            return new VectorRectangle(rect);
        }

        public static implicit operator RectangleF(VectorRectangle rect)
        {
            return new RectangleF((float) rect.X, (float) rect.Y, (float) rect.Width, (float) rect.Height);
        }

        public static explicit operator Rectangle(VectorRectangle rect)
        {
            return new Rectangle((int) rect.X, (int) rect.Y, (int) rect.Width, (int) rect.Height);
        }

        public Rectangle Truncate()
        {
            return new Rectangle((int) this.x, (int) this.y, (int) this.width, (int) this.height);
        }

        public Rectangle Round()
        {
            return new Rectangle((int) Math.Round(this.x, 0), (int) Math.Round(this.y, 0), (int) Math.Round(this.width, 0), (int) Math.Round(this.height, 0));
        }
    }
}

